package io.itit.ecp.admin.provide.action.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.provide.action.req.ProjectMeterStaticsQueryReq;
import io.itit.ecp.admin.provide.action.resp.ProjectMeterStaticsDetailRes;
import io.itit.ecp.admin.provide.action.resp.ProjectMeterStaticsRes;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.*;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.IQueryPage;
import io.itit.grass.core.server.entity.UserEntity;
import io.itit.grass.core.server.service.IUserService;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 项目计量统计
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/ecp-admin/projectMeterStatics")
public class ProjectMeterStaticsController {

    @Resource
    private IMeterDeviceService meterDeviceService;

    @Resource
    private ISceneProjectService sceneProjectService;

    @Resource
    private IEnergyConsumptionTypeService energyConsumptionTypeService;

    @Resource
    private IUserService userService;

    @Resource
    private ISceneFloorService sceneFloorService;

    @Resource
    private ISceneEdificeService sceneEdificeService;

    @Resource
    private ISceneRoomService sceneRoomService;

    @Resource
    private IEnergyDataService energyDataService;

    @RequestMapping("queryPage")
    public ResultResp<IPage<ProjectMeterStaticsRes>> page(@RequestBody @Validated(IQueryPage.class) ProjectMeterStaticsQueryReq req) {
        Page<ProjectMeterStaticsRes> page = buildQW(req).joinPage(PageUtils.getPage(req, ProjectMeterStaticsRes.class), ProjectMeterStaticsRes.class);
        setValues(page.getRecords(), req.getEnergyTypeId());
        return ResultResp.success(page);
    }

    private void setValues(List<ProjectMeterStaticsRes> list, String energyTypeId) {
        Set<String> projectIds = list.stream().map(ProjectMeterStaticsRes::getId).collect(Collectors.toSet());
        Map<String, List<MeterDeviceEntity>> meterDeviceMap = Collections.emptyMap();
        if (!projectIds.isEmpty()) {
            meterDeviceMap = meterDeviceService.list(new LambdaQueryWrapper<MeterDeviceEntity>()
                            .in(MeterDeviceEntity::getSceneProjectId, projectIds)
                            .eq(MeterDeviceEntity::getDelFlag, IMeterDeviceEnums.DelFlag.delFlag1.delFlag)
                            .eq(StringUtils.isNotEmpty(energyTypeId), MeterDeviceEntity::getEnergyTypeId, energyTypeId))
                    .stream().collect(Collectors.groupingBy(MeterDeviceEntity::getSceneProjectId));
        }
        for (ProjectMeterStaticsRes item : list) {
            List<MeterDeviceEntity> deviceEntities = meterDeviceMap.getOrDefault(item.getId(), Collections.emptyList());
            item.setDeviceNum(deviceEntities.size());
            if (item.getDeviceNum() > 0) {
                item.setEnergyTypeId(deviceEntities.get(0).getEnergyTypeId());
                EnergyConsumptionTypeEntity energyTypeEntity = energyConsumptionTypeService.getById(item.getEnergyTypeId());
                if (Objects.nonNull(energyTypeEntity)) {
                    item.setEnergyTypeName(energyTypeEntity.getEnergyName());
                    item.setUnit(energyTypeEntity.getEnergyUnit());
                }
            }
        }
    }

    @ApiOperation("详情")
    @GetMapping("detail")
    public ResultResp<ProjectMeterStaticsDetailRes> detail(@RequestParam String ids, String solidifyDate) throws Exception {
        List<EnergyDataEntity> energyDataEntities = energyDataService.listByIds(Arrays.stream(StringUtils.split(ids, ",")).collect(Collectors.toSet()));
        SceneProjectEntity projectEntity = sceneProjectService.getById(energyDataEntities.get(0).getSceneProjectId());
        if (Objects.isNull(projectEntity)) {
            return ResultResp.fail("项目不存在");
        }
        ProjectMeterStaticsDetailRes detailRes = new ProjectMeterStaticsDetailRes();
        detailRes.setId(projectEntity.getId());
        detailRes.setSceneProjectName(projectEntity.getProjectName());
        detailRes.setAddress(projectEntity.getAddress());
        detailRes.setMobilePhone(projectEntity.getMobilePhone());
        detailRes.setStaticsTime(DateUtils.parseDate(solidifyDate, "yyyy-MM-dd HH", "yyyy-MM-dd HH:mm", "yyyy/MM/dd", "yyyy/MM", "yyyy"));
        detailRes.setStatus(projectEntity.getStatus());
        detailRes.setUserName(projectEntity.getStatus());
        UserEntity user = userService.getById(projectEntity.getUserId());
        if (Objects.nonNull(user)) {
            detailRes.setUserName(user.getUserName());
        }
        Set<String> meterIds = energyDataEntities.stream().map(EnergyDataEntity::getMeterDeviceId).collect(Collectors.toSet());
        List<MeterDeviceEntity> meterDeviceEntities = CollectionUtils.isEmpty(meterIds) ? Collections.emptyList() :
                meterDeviceService.list(new LambdaQueryWrapper<MeterDeviceEntity>()
                        .in(MeterDeviceEntity::getId, meterIds)
                        .eq(MeterDeviceEntity::getDelFlag, IMeterDeviceEnums.DelFlag.delFlag1.delFlag)
                );
        Set<String> edificeIds = meterDeviceEntities.stream().map(MeterDeviceEntity::getSceneEdificeId)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toSet());
        List<SceneEdificeEntity> edificeEntities = edificeIds.isEmpty() ? Collections.emptyList() :
                sceneEdificeService.list(new LambdaQueryWrapper<SceneEdificeEntity>().in(SceneEdificeEntity::getId, edificeIds));
        Set<String> floorIds = meterDeviceEntities.stream().map(MeterDeviceEntity::getSceneFloorId)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toSet());
        List<SceneFloorEntity> floorEntities = floorIds.isEmpty() ? Collections.emptyList() :
                sceneFloorService.list(new LambdaQueryWrapper<SceneFloorEntity>().in(SceneFloorEntity::getId, floorIds));

        Set<String> roomIds = meterDeviceEntities.stream().map(MeterDeviceEntity::getSceneRoomId)
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toSet());
        List<SceneRoomEntity> roomList = roomIds.isEmpty() ? Collections.emptyList() :
                sceneRoomService.list(new LambdaQueryWrapper<SceneRoomEntity>().eq(SceneRoomEntity::getId, roomIds));
        List<ProjectMeterStaticsDetailRes.MeterDeviceDetail> list = meterDeviceEntities.stream().map(item -> {
                    ProjectMeterStaticsDetailRes.MeterDeviceDetail meterDeviceDetail = new ProjectMeterStaticsDetailRes.MeterDeviceDetail()
                            .setDeviceCode(item.getDeviceCode())
                            .setRoomInfo(CompanyMeterStatisticController.getRoomInfo(item, roomList, floorEntities, edificeEntities))
                            .setDeviceName(item.getDeviceName())
                            .setIsFocus(item.getIsFocus())
                            .setReadMeterTag(item.getReadMeterTag());
                    List<EnergyDataEntity> dataEntities = energyDataEntities.stream().filter(energyData -> StringUtils.equals(energyData.getMeterDeviceId(), item.getId()))
                            .collect(Collectors.toList());
                    Date staticsDate = CollectionUtils.isEmpty(dataEntities) ? detailRes.getStaticsTime() : dataEntities.get(0).getSolidifyDate();
                    meterDeviceDetail.setDateTime(staticsDate);
                    meterDeviceDetail.setValue(dataEntities.stream().map(EnergyDataEntity::getMeterValue).reduce(BigDecimal.ZERO, BigDecimal::add));
                    meterDeviceDetail.setUnit(CollectionUtils.isEmpty(dataEntities) ? null : dataEntities.get(0).getEnergyTypeUnit());
                    return meterDeviceDetail;
                }

        ).collect(Collectors.toList());
        detailRes.setMeterDeviceDetails(list);
        return ResultResp.success(detailRes);
    }


    @ApiOperation("导出")
    @PostMapping("export")
    public void export(@RequestBody ProjectMeterStaticsQueryReq req, HttpServletResponse response) {
        List<ProjectMeterStaticsRes> respList = buildQW(req).joinList(ProjectMeterStaticsRes.class);
        setValues(respList, req.getEnergyTypeId());
        ExcelXSSFUtil.export("projectMeterStaticsExport", JsonUtil.toJson(respList), response);
    }


    private JoinLambdaWrapper<SceneProjectEntity> buildQW(ProjectMeterStaticsQueryReq req) {
        return Joins.of(SceneProjectEntity.class)
                .eq(StringUtils.isNotEmpty(req.getId()), SceneProjectEntity::getId, req.getId())
                .gt(StringUtils.isNotEmpty(req.getStartTime()), SceneProjectEntity::getCreateTm, req.getStartTime())
                .lt(StringUtils.isNotEmpty(req.getEndTime()), SceneProjectEntity::getCreateTm, req.getEndTime())
                .orderByDesc(StringUtils.isEmpty(req.getSortColumn()), SceneProjectEntity::getCreateTm);
    }
}
